<?php

// uses
class Agilet
{

	/**
	 * container
	 * @var registry
	 */
	static protected $_registry = array();

	/**
	 * protected app base url
	 * @var string
	 */
	static protected $_appUrl = '/agilet/';

	/**
	 * static base url liked to our media server
	 * @var string
	 */
	static protected $_staticUrl = '/agilet/';

	/**
	 * static base url liked to our media server
	 * @var string
	 */
	static protected $_mediaUrl = '/agilet/';

	/**
	 * get static base url
	 * @return string
	 */
	static public function getStaticUrl()
	{
		return self::$_staticUrl;
	}

	/**
	 * set static base url
	 * @param string $staticUrl
	 * @return void
	 */
	static public function setStaticUrl($staticUrl)
	{
		self::$_staticUrl = $staticUrl;
	}

	/**
	 * @return string
	 */
	static public function getAppUrl()
	{
		return self::$_appUrl;
	}

	/**
	 * @param  string  $baseUrl
	 * @return void
	 */
	static public function setAppUrl($appUrl)
	{
		self::$_appUrl = $appUrl;
	}

	/**
	 * @return string
	 */
	static public function getMediaUrl()
	{
		return self::$_mediaUrl;
	}

	/**
	 * @param  string  $baseUrl
	 * @return void
	 */
	static public function seMediaUrl($mediaUrl)
	{
		self::$_mediaUrl = $mediaUrl;
	}

	/**
	 * rerieves a variable regiester to registry
	 */
	static public function getRegistry($key, $default = null)
	{
		return isset(self::$_registry[$key]) ? self::$_registry[$key] : $default;
	}

	static public function setRegistry($key, $value)
	{
		self::$_registry[$key] = $value;
	}

	/**
	 * load configuration file
	 * it seems always return array
	 * @return array
	 */
	static public function loadConfig($file, $offset = null, $dir = null)
	{
		if (null == $dir)
		{
			$dir = CONFIG_PATH;
		}

		$filename = $dir . '/' . $file;

		if (!file_exists($filename))
		{
			throw new Exception("Invalid configuration file under config directory $filename");
		}

		$data =
		include $filename;

		if ($offset)
		{
			if (!isset($data[$offset]))
			{

				throw new Exception("invalid configuration offset $file:$offset");
			}
			return $data[$offset];
		}
		return $data;
	}

	static public function hasClass($class_name)
	{
		return class_exists($class_name) or self::__autoload($class_name);
	}

	/**
	 * find class
	 * @param string $class_name
	 * @return true/false
	 */
	static public function requireClass($path, $module = 'system')
	{
		return class_exists($class_name) or self::__autoload($class_name);
	}

	/**
	 * factory a resource object
	 *
	 * @param      string     $name
	 * @param      string     $ext
	 * @return     Object
	 */
	static public function __resource($name, $ext = null)
	{
		if (self::hasClass($class_name = self::sanitizeClass($name)))
		{
			return new $class_name;
		}

		throw new Exception("class $name $ext does not exists!");
	}

	/**
	 * @param     string $name
	 * @param     string $ext
	 * @return    string class name
	 */
	static public function sanitizeClass($name, $ext)
	{
		if ($ext)
		{
			$name = trim(str_replace('@', '.' . $ext . '.', $name), '.');
		}
		return implode('_', array_map('ucfirst', explode('.', $name)));
	}

	/**
	 * DO NOT CALL METHOD START WITH __ in your class
	 */
	static public function __bootstrap()
	{
		spl_autoload_register(array(
			'Agilet',
			'__autoload'
		));

		/**
		 * register error handler
		 */
		set_error_handler(array(
			'Agilet',
			'__handle_error'
		));

		/**
		 * register exception handler
		 */
		set_exception_handler(array(
			'Agilet',
			'__handle_exception'
		));

		/**
		 * register shutdown handler
		 */
		register_shutdown_function(array(
			'Agilet',
			'__handle_shutdown'
		));

		Session::start();

	}

	static public function __autoload($class_name)
	{
		$paths = array(
			APP_PATH . '/classes',
			APP_PATH . '/classes/system',
			LIBRARY_PATH . '/classes/system',
			LIBRARY_PATH . '/classes',
		);

		$filename = str_replace('_', '/', strtolower($class_name . '.php'));

		foreach ($paths as $path)
		{
			if (file_exists($file = $path . '/' . $filename))
			{
				require_once $file;
				return TRUE;
			}
		}

		if (file_exists($file = LIBRARY_PATH . '/' . str_replace('_', '/', $class_name . '.php')))
		{
			require_once $file;
			return TRUE;
		}

		return FALSE;

	}

	/**
	 * handle error
	 * @param  int     $errorno
	 * @param  string  $errstr
	 * @param  string  $errfile
	 * @param  int     $errline
	 * @param  handle  $errcontext
	 */
	static public function __handle_error($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
	{
		Logger::inst() -> write(Logger::ERROR, sprintf('[%1$d] %2$s (%3$s) [%4$d]' . PHP_EOL . '%5$s', $errno, $errstr, $errfile, $errline, debug::backtrace()));
		$level = Logger::INFO;
		$fatal = FALSE;

		switch ($errno) {
			case E_USER_NOTICE :
			case E_NOTICE :
				$level = Logger::NOTICE;
				break;
			default :
			case E_USER_WARNING :
			case E_WARNING :
			case E_COMPILE_WARNING :
			case E_CORE_WARNING :
			case E_DEPRECATED :
			case E_STRICT :
			case E_USER_DEPRECATED :
				$level = Logger::WARN;
				break;
			case E_COMPILE_ERROR :
			case E_CORE_ERROR :
			case E_ERROR :
			case E_PARSE :
			case E_RECOVERABLE_ERROR :
			case E_USER_ERROR :
				$level = Logger::ERR;
				$fatal = TRUE;
				break;
		}

		if ($fatal)
		{
			self::sendFatalError();
		}
		return 1;
	}

	static public function sendFatalError()
	{
		// Clean any previous output from buffer
		while (ob_get_level() > 0)
		{
			ob_end_clean();
		}

		ob_get_clean();

		echo View::render(array(), 'error/fatal');
		die(1);
	}

	/**
	 * handle exception
	 * @param Exception $exception
	 * @return true/false
	 */
	static public function __handle_exception($exception)
	{
		Logger::inst() -> write(Logger::ERROR, debug::backtrace() . PHP_EOL . $exception -> getMessage());
		return 0;
	}

	/**
	 * handle shutdown
	 */
	static public function __handle_shutdown()
	{

		/**
		 * code here
		 */
		Logger::inst() -> flush();
	}

	static public function execute()
	{
		$request = Request::initiator();

		try
		{
			$request -> execute();
		}
		catch(Exception $e)
		{
			$request -> execute('error/404');
		}

		// process with layout container.
		$format = $request -> getParam('format');
		$is_ajax = $request -> isAjax();

		switch($format) {
			case 'json' :
			case 'jsonp' :
				return json_encode(array(
					'html' => $request -> response,
					'error' => 0,
					'message' => ''
				));
				break;
			case 'html' :
			case 'xhtml' :
			case 'xml' :
				return $request -> response;
				break;
			case null :
			default :
				$template = Template::inst();
				return $template -> execute($request);
		}
	}

	static public function emit($event)
	{

	}

	static public function getUrl($path, $params = null)
	{
		if (strpos($path, '://') == false)
		{
			$path = self::getAppUrl() . $path;
		}

		if ($params != null)
		{
			$path .= '?' . http_build_query($params);
		}
		return $path;
	}

	static protected $_helpers = array();
	/**
	 * @param string $name
	 * @return class
	 */
	static public function getHelper($name)
	{
		if (!isset(self::$_helpers[$name]))
		{
			$class = 'Helper_' . ucfirst($name);
			self::$_helpers[$name] = new $class;
		}
		return self::$_helpers[$name];
	}

	static public function getViewerId()
	{
		if (isset($_SESSION['user_id']))
		{
			return intval($_SESSION['user_id']);
		}
		return 0;
	}

	/**
	 * @var Model_User
	 */
	private static $_viewer = null;

	/**
	 * @return Model_User
	 */
	static public function getViewer()
	{
		if (null == self::$_viewer)
		{
			$user = new Model_User;

			$id = self::getViewerId();

			if ($id)
			{
				$user -> load($id);
			}

			self::$_viewer = $user;
		}
		return self::$_viewer;
	}

}
